package com.zenithmind.common.handler;

import com.zenithmind.common.exception.*;
import com.zenithmind.common.result.Result;
import com.zenithmind.common.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.security.access.AccessDeniedException;

import java.sql.SQLException;

/**
 * 通用全局异常处理基类
 * 提供基本的异常处理逻辑，子类可以继承并扩展
 */
@Slf4j
public class CommonGlobalExceptionHandler {

    /**
     * 处理API异常基类
     */
    @ExceptionHandler(ApiException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleApiException(ApiException ex) {
        log.error("API异常: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }

    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleBusinessException(BusinessException ex) {
        log.error("业务异常: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }

    /**
     * 处理资源不存在异常
     */
    @ExceptionHandler(NotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result<Void> handleNotFoundException(NotFoundException ex) {
        log.warn("资源不存在: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }
    
    /**
     * 处理参数验证异常
     */
    @ExceptionHandler(ValidationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleValidationException(ValidationException ex) {
        log.warn("参数验证失败: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }
    
    /**
     * 处理未认证异常
     */
    @ExceptionHandler(UnauthorizedException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result<Void> handleUnauthorizedException(UnauthorizedException ex) {
        log.warn("未认证访问: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }
    
    /**
     * 处理权限不足异常
     */
    @ExceptionHandler(ForbiddenException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result<Void> handleForbiddenException(ForbiddenException ex) {
        log.warn("权限不足: {}", ex.getMessage());
        return Result.fail(ex.getCode(), ex.getMessage(), null);
    }
    
    /**
     * 处理参数校验异常（@Valid注解）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleValidationExceptions(MethodArgumentNotValidException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        String errorMessage = fieldError != null ? fieldError.getDefaultMessage() : "参数验证失败";
        log.warn("参数验证失败: {}", errorMessage);
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), errorMessage, null);
    }
    
    /**
     * 处理请求参数缺失异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.warn("请求参数缺失: {}", ex.getMessage());
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), "请求参数缺失: " + ex.getParameterName(), null);
    }
    
    /**
     * 处理类型转换异常
     */
    @ExceptionHandler(TypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleTypeMismatchException(TypeMismatchException ex) {
        log.warn("类型转换错误: {}", ex.getMessage());
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), "参数类型错误: " + ex.getPropertyName(), null);
    }
    
    /**
     * 处理HTTP消息不可读异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.warn("HTTP消息不可读: {}", ex.getMessage());
        return Result.fail(ResultCode.PARAM_ERROR.getCode(), "请求体不可读或格式错误", null);
    }
    
    /**
     * 处理HTTP请求方法不支持异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Result<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        log.warn("请求方法不支持: {}", ex.getMessage());
        return Result.fail(ResultCode.METHOD_NOT_ALLOWED.getCode(), 
                "不支持的请求方法: " + ex.getMethod(), null);
    }
    
    /**
     * 处理HTTP媒体类型不支持异常
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    public Result<Void> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException ex) {
        log.warn("不支持的媒体类型: {}", ex.getMessage());
        return Result.fail(ResultCode.UNSUPPORTED_MEDIA_TYPE.getCode(), 
                "不支持的媒体类型: " + ex.getContentType(), null);
    }
    
    /**
     * 处理所有数据库相关异常（SQL异常、数据访问异常等）
     */
    @ExceptionHandler({SQLException.class, DataAccessException.class, BadSqlGrammarException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Void> handleDatabaseException(Exception ex) {
        log.error("数据库访问异常: {}", ex.getMessage(), ex);
        return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "数据库操作异常", null);
    }
    
    /**
     * 处理数据完整性违反异常
     */
    @ExceptionHandler(DataIntegrityViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
        log.error("数据完整性违反: {}", ex.getMessage(), ex);
        return Result.fail(ResultCode.BAD_REQUEST.getCode(), "数据完整性约束违反", null);
    }
    
    /**
     * 处理唯一键重复异常
     */
    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Void> handleDuplicateKeyException(DuplicateKeyException ex) {
        log.warn("唯一键冲突: {}", ex.getMessage(), ex);
        return Result.fail(ResultCode.CONFLICT.getCode(), "数据已存在，请勿重复提交", null);
    }

    /**
     * 处理运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> handleRuntimeException(RuntimeException e) {
        log.error("运行时异常", e);
        return Result.fail(ResultCode.INTERNAL_SERVER_ERROR);
    }

    /**
     * 处理权限不足异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result<String> handleAccessDeniedException(AccessDeniedException e) {
        log.warn("权限不足: {}", e.getMessage());
        return Result.fail(ResultCode.FORBIDDEN);
    }

    /**
     * 处理所有其他异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> handleException(Exception e) {
        log.error("未处理异常", e);
        return Result.fail(ResultCode.INTERNAL_SERVER_ERROR);
    }
} 